package crawler;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.sql.*;

public class Index {
			
	private static int _bodyPoints = 1, _headPoints = 5, dbCounter=0;
	private static int _docNumber = 0;
	public static HashMap<String, Integer> _indexer = new HashMap<String, Integer>(); 			// Word	, Score
	public static HashMap<String, Integer> _dictionary = new HashMap<String, Integer>();// Word	, WordID
//	public static HashMap<String, Integer> _dictionaryTemp = new HashMap<String, Integer>();// Word	, WordID
	private static String _url;
	private static boolean dbConnected = false;
	
	public static void newDocumentToProcess(ParsedStuff parsedStuff) {
		URL url_aux = parsedStuff.getURLid();
		_url = url_aux.toString();
		_docNumber++;
		
		// TITLE HANDLER
		createTableWordsAndPoints(parsedStuff.getHead(), _headPoints);

		// BODY HANDLER
		createTableWordsAndPoints(parsedStuff.getBody(), _bodyPoints);
//		createTableWordsAndPoints("s a a a a a a a a a", _bodyPoints);

		// Populate DataBase
		putInfoIntoDataBase();
	}

	public static void createTableWordsAndPoints(String sentence, int points) {
		ArrayList<String> arrayList = new ArrayList<String>();
		Integer previousScore;
		int maxCurrentID;

		arrayList = processTokenizer(sentence);
		for (String str : arrayList) {
			if (_indexer.containsKey(str)) {
				previousScore = _indexer.get(str);
				_indexer.remove(str);
				_indexer.put(str, previousScore + points);
			} else{
				maxCurrentID = _dictionary.size();
				_dictionary.put(str, maxCurrentID++);
				_indexer.put(str, points);
			}
		}
	}

	public static void putInfoIntoDataBase() {
		// connect to DB
		System.out.println("Inserting values in Mysql database table!");
		Connection con = null;
		String url = "jdbc:mysql://192.168.243.97:3306/";
		String db = "document";
		String driver = "com.mysql.jdbc.Driver";
		try{
			Class.forName(driver);
			con = DriverManager.getConnection(url+db,"root","student");
			try{
				Statement st = con.createStatement();
				for(Map.Entry<String, Integer> entry : _dictionary.entrySet()){
					ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM Dictionary WHERE WordID=" + getWordIDFromDictionary(entry.getKey()));
					
//					System.out.println("XXXXXXXXXXXXXXXXXXXXXXXX" +rs.getInt(1));
					if(rs.getInt(1) == 0)
						st.executeUpdate("INSERT INTO Dictionary VALUES("+entry.getValue()+",'"+entry.getKey()+"')");
				}
				
				System.out.println("Dictionary Updated");
				
				//INDEXER TABLE
				System.out.println("INSERT INTO Indexer VALUES("+_docNumber+",'"+_url+"','"+Arrays.toString(convertToByteArray(_indexer))+"')");
				st.executeUpdate("INSERT INTO Indexer VALUES("+_docNumber+",'"+_url+"','"+Arrays.toString(convertToByteArray(_indexer))+"')");
				System.out.println("Indexer Inserted");

				//INVERTED INDEXER TABLE
				for(Map.Entry<String, Integer> entry : _indexer.entrySet()){
					System.out.println("SELECT COUNT(*) FROM InvertedIndexer WHERE WordID='" + getWordIDFromDictionary(entry.getKey()) + "'");
					ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM InvertedIndexer WHERE WordID='" + getWordIDFromDictionary(entry.getKey()) + "' AND DocID='"+ _docNumber + "'");
					//rs.next();
//					System.out.println("LLL" + rs.getInt(1));
					if(rs.getInt(1) == 0)
						st.executeUpdate("INSERT IGNORE INTO InvertedIndexer VALUES("+getWordIDFromDictionary(entry.getKey())+","+_docNumber+")");
				}
				System.out.println("Inverted Indexer Updated");
			
			}
			catch (SQLException s){
				System.out.println("SQL statement is not executed!");
				s.printStackTrace();
			}
		}
		catch (Exception e){
			e.printStackTrace();
		}

//			WILL TERMINATE THE BD CONNECTION ON ANOTHER CLASS AT THE END
	}

//	public static void MergeDictionary(){
//		if(_dictionary.containsKey(key))
//	}
//	
	public static ArrayList<String> processTokenizer(String sentence) {
		String nextWord;
		ArrayList<String> arrayList = new ArrayList<String>();

		StringTokenizer st = new StringTokenizer(sentence);
		while (st.hasMoreTokens()) {
			nextWord = st.nextToken();

			if(IsWordPermited(nextWord)){
				if (!arrayList.isEmpty()){
					if (!arrayList.contains(nextWord))
						arrayList.add(nextWord);
				}else{
					arrayList.add(nextWord);
				}
			}
		}

		return arrayList;
	}

	private static boolean IsWordPermited(String nextWord) {
		
		return true;
	}

	private static int getWordIDFromDictionary(String word) {
		// lookup in dictionary for word and get its id
		return _dictionary.get(word);
	}

	private static byte[] getBytes(int val) {
		// int -> 4 bytes
		// MSB ........ LSB
		// B3 B2 B1 B0
		// example: 37 -> 0x00 0x00 0x00 0x25
		return new byte[] { (byte) (val >> 24), (byte) (val >> 16),
				(byte) (val >> 8), (byte) val };
	}

	private static String toString(byte[] arr) {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for (int i = 0; i < arr.length; ++i) {
			sb.append(Integer.toHexString(arr[i] & 0xFF));
			if (i < arr.length - 1) {
				sb.append(',');
			}
		}
		sb.append("]");
		return sb.toString();
	}

	public static byte[] convertToByteArray(HashMap<String, Integer> map)
			throws IOException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		for (Map.Entry<String, Integer> entry : map.entrySet()) {
			String word = entry.getKey();
			Integer score = entry.getValue();
			int wordID = getWordIDFromDictionary(word);
			baos.write(getBytes(wordID));
			baos.write(getBytes(score));
		}
		return baos.toByteArray();
	}

//	public static void main(String[] args) throws IOException {
//		newDocumentToProcess(null);
//
//		System.out.println("_dictionary");
//		for(Map.Entry<String, Integer> entry : _dictionary.entrySet()){
//			System.out.println("Word = " + entry.getKey() + ", Id = " + entry.getValue());
//		}
//		
//		System.out.println("_indexer");
//		for(Map.Entry<String, Integer> entry : _indexer.entrySet()){
//			System.out.println("Word = " + entry.getKey() + ", Score = " + entry.getValue());
//		}
//	}

					// IF I HAVE TIME:
	// tenho de fazer um range de mapas para ser mais eficiente
	// como eh que vez as palavras, eh so ver as palavras k sao nomes?
}
